<template>
  <div>
    <!-- 地图容器 -->
    <div id="cesiumContainer" :class="{'cesiumContainer_right': left_show}">
      <!-- 剖面分析结果图 -->
      <Scetion :data='section_data' v-if='section_show' id='section_result' />
    </div>
    <!-- 鼠标位置信息 -->
    <div id='mouse_position' v-show="mouse_hover">
      经度:{{longitude}}&nbsp;&nbsp;纬度:{{latitude}}&nbsp;&nbsp;视高:{{height}}km
    </div>
    <!-- 操作菜单 -->
    <div id="menu">
      <dv-border-box-10>
        <div class="item_list">
          <div class="menu-item" @click="menu_weather">
            <i class="iconfont icon-tianqi fw-600" />
            <div>天气效果</div>
          </div>
          <div class="menu-item" @click="menu_particle">
            <i class="iconfont icon-texiao" />
            <div>场景特效</div>
          </div>
          <div class="menu-item" @click="menu_length">
            <i class="iconfont icon-juli" />
            <div>距离测量</div>
          </div>
          <div class="menu-item" @click="menu_area">
            <i class="iconfont icon-mianji" />
            <div>面积测量</div>
          </div>
          <div class="menu-item" @click="menu_section">
            <i class="iconfont icon-poumian" />
            <div>剖面分析</div>
          </div>
          <div class="menu-item" @click="menu_visual_area">
            <i class="iconfont icon-keshi" />
            <div>可视域分析</div>
          </div>
          <div class="menu-item" @click="menu_visible">
            <i class="iconfont icon-tongshi" />
            <div>通视分析</div>
          </div>
          <div class="menu-item" @click="menu_capture">
            <i class="iconfont icon-jietu" />
            <div>场景截图</div>
          </div>
          <div class="menu-item" @click="menu_clear">
            <i class="iconfont icon-qingping fw-600" />
            <div>清空屏幕</div>
          </div>
        </div>
      </dv-border-box-10>
    </div>
    <!-- 天气效果选择弹框 -->
    <div v-show='showDialog_weather' class="dialog weather_dialog">
      <div class="title">
        天气效果
        <i class="el-icon-close" @click="showDialog_weather=false" />
      </div>
      <el-radio-group v-model="weather_option" @input="weather_change">
        <el-radio-button label="晴天"></el-radio-button>
        <el-radio-button label="雾天"></el-radio-button>
        <el-radio-button label="雨天"></el-radio-button>
        <el-radio-button label="雪天"></el-radio-button>
      </el-radio-group>
    </div>

    <!-- 场景特效选择弹框 - 粒子特效 -->
    <div v-show='showDialog_particle' class="dialog particle_dialog">
      <div class="title">
        场景特效
        <i class="el-icon-close" @click="showDialog_particle=false" />
      </div>
      <el-radio-group v-model="particle_option" @input="particle_change">
        <el-radio-button label="樱花"></el-radio-button>
        <el-radio-button label="桂花"></el-radio-button>
        <el-radio-button label="烟花"></el-radio-button>
      </el-radio-group>
    </div>

    <!-- 左侧 -->
    <div id='info-box' v-show="left_show">
      <i class="iconfont icon-shouqi shouqi" @click="left_show=false" />
      <div class="item">
        <div class="title">黄鹤楼公园</div>
        <div class="content">
          <div class="content-item">
            <i class="iconfont icon-yanchu" />
            <div class="value">1174场</div>
            <div class="type">实景演出</div>
          </div>
          <div class="content-item">
            <i class="iconfont icon-wenchuang" />
            <div class="value">200余款</div>
            <div class="type">文创产品</div>
          </div>
          <div class="content-item">
            <i class="iconfont icon-hotsearch" />
            <div class="value">50余次</div>
            <div class="type">微博热搜</div>
          </div>
        </div>
      </div>
      <div class="item">
        <div class="title">图表数据</div>
        <PeopleChart style='margin-top: 12px' />
      </div>
      <div class="item">
        <div class="title">热点词云</div>
        <WordCloud />
      </div>
    </div>
    <i class="iconfont icon-shouqi zhankai" v-show="!left_show" @click="left_show=true" />
  </div>
</template>

<script>
import './weather/fog.js'
import './weather/rain.js'
import './weather/snow.js'
import PeopleChart from "@/components/Echart/YellowCraneTower";
import WordCloud from "@/components/Echart/TowerWordCloud/index.vue"
import Scetion from '@/components/Echart/Section'

/* 地图相关变量 */
var cesium_token='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0MTZhYTU2OC1iYWVkLTQ3ZTQtOGI3MC0wOGU4M2ViMTg3M2UiLCJpZCI6MTYwMzgwLCJpYXQiOjE2OTIwMjg5NTB9.DLqrhU4mTDXYMzcz7Js5aWXngoEO_3j2h3O9c26YiMM'
var viewer=null;
/* 天气效果相关 */
var weather=null;
/* 粒子烟花相关 */
var fireworks=[]
var particleCanvas;
const particlePixelSize=new Cesium.Cartesian2(7.0,7.0);  //粒子大小
const burstNum=400.0;  //爆炸粒子个数
const lifetime=10.0;    //粒子系统发射粒子的时间
const numberOfFireworks=20.0;  //烟花个数
const modelMatrix=Cesium.Transforms.eastNorthUpToFixedFrame(
  Cesium.Cartesian3.fromDegrees(114.29708,30.54706)
);
const emitterInitialLocation=new Cesium.Cartesian3(0.0,0.0,100.0);//粒子发射器高度
var flowerGravityScratch=new Cesium.Cartesian3();
/* 粒子落花 */
var flower;
const flowerRadius=6000.0; //落花的范围半径
const minimumFlowerImageSize=new Cesium.Cartesian2(10,10); //落花最小尺寸
const maximumFlowerImageSize=new Cesium.Cartesian2(20,20); //落花最大尺寸
/* 绘制相关 */
var positions=[];	//用来存储要计算距离的点
var activeShapePoints=[]; //动态点数组
var activeShape;    //动态图形
var floatingPoint;  //第一个点 判断是否开始获取鼠标移动结束位置并添加至activeShapePoints
var p=[];//用来存储要计算面积的点
/* 距离、面积测量相关 */
var pCartographic=[];
const radiansPerDegree=Math.PI/180.0; //角度转化为弧度(rad) 
const degreesPerRadian=180.0/Math.PI; //弧度转化为角度
/* 剖面分析相关 */
var star,end;//绘制实体
/* 可视域分析相关 */
var arrViewField=[]; //存储分析结果
const viewModel={ verticalAngle: 90,horizontalAngle: 120 }; // 分析参数
/* 通视分析相关 */
var positions_visble=[]; //存储观察点和目标点


export default {
  data() {
    return {
      //鼠标位置信息
      mouse_hover: false,
      longitude: '', //经度
      latitude: '',  //纬度
      height: '',    //视高
      //天气效果选择弹框
      showDialog_weather: false,
      weather_option: '晴天',
      //场景特效选择弹框
      showDialog_particle: false,
      particle_option: '樱花',
      //距离测量
      handler_line: null,
      //面积测量
      handler_area: null,
      //剖面分析
      handler_section: null,
      section_show: false,
      section_data: {},
      //通视分析
      handler_visible: null,
      //左侧图表信息框
      left_show: true,
    };
  },
  components: {
    PeopleChart,
    WordCloud,
    Scetion
  },
  mounted() {
    this.initMapCon();
    this.listenMouseMove();
    this.add3dTiles();
  },
  methods: {
    //初始化Cesium Viewer 
    initMapCon() {
      Cesium.Ion.defaultAccessToken=cesium_token
      viewer=new Cesium.Viewer("cesiumContainer",{
        geocoder: false,              //是否显示位置查找工具
        homeButton: false,            //是否显示首页位置工具
        sceneModePicker: false,       //是否显示视角模式切换工具
        baseLayerPicker: false,       //是否显示默认图层选择工具
        navigationHelpButton: false,  //是否显示导航帮助工具
        animation: false,             //是否显示动画工具
        shouldAnimate: true,  //必须开启
        timeline: false,              //是否显示时间轴工具
        fullscreenButton: false,      //是否显示全屏按钮工具
        infoBox: false,
        terrainProvider: Cesium.createWorldTerrain({
          requestVertexNormals: true //可视化坡度，必须开启
        }),
        contextOptions: {
          webgl: {
            alpha: true, //背景透明
          }
        },
      })
      //视图模式
      viewer.scene.mode=Cesium.SceneMode.SCENE3D;
      //开启地形检测
      viewer.scene.globe.depthTestAgainstTerrain=true;
      //关闭天空盒-背景透明
      viewer.scene.skyBox.show=false;
      //设置背景透明
      viewer.scene.backgroundColor=Cesium.Color.TRANSPARENT;
      //设置相机初始位置
      viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(114.2970855236,30.5470658877,400),
        orientation: {
          heading: Cesium.Math.toRadians(20.0), // 方向
          pitch: Cesium.Math.toRadians(-90.0),// 倾斜角度
          roll: 0
        }
      });
    },

    //监听鼠标移动, 显示位置信息
    listenMouseMove() {
      var handler=new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction((movement) => {
        //捕获椭球体，将笛卡尔二维平面坐标转为椭球体的笛卡尔三维坐标，返回球体表面的点
        let ellipsoid=viewer.scene.globe.ellipsoid;
        let cartesian=viewer.camera.pickEllipsoid(movement.endPosition,ellipsoid);
        if(cartesian) {
          this.mouse_hover=true;
          //将笛卡尔三维坐标转为地图坐标（弧度）
          let cartographic=ellipsoid.cartesianToCartographic(cartesian);
          //将地图坐标（弧度）转为十进制的度数
          //经度
          this.longitude=Cesium.Math.toDegrees(cartographic.longitude).toFixed(4);
          //纬度
          this.latitude=Cesium.Math.toDegrees(cartographic.latitude).toFixed(4);
          //视高
          this.height=(viewer.camera.positionCartographic.height/1000).toFixed(2);
        }
        else this.mouse_hover=false;
      },Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    },

    //加载黄鹤楼3D Tiles
    add3dTiles() {
      //加载
      var tileset=viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
        url: Cesium.IonResource.fromAssetId(2161640)
      }));
      //定位
      tileset.readyPromise.then(function(tileset) {
        viewer.zoomTo(tileset);
      });
    },

    //清屏 - 菜单按钮
    menu_clear() {
      //移除天气显示效果
      this.showDialog_weather=false;
      viewer.shadows=false;
      if(weather) weather.destroy();
      //移除场景特效
      this.showDialog_particle=false;
      //移除粒子落花
      if(flower) flower.destroy();
      //移除粒子烟花
      for(var i=0;i<fireworks.length;i++) {
        fireworks[i].destroy()
      }
      fireworks=[];
      //移除绘制内容
      viewer.entities.removeAll();
      //移除距离测量
      if(this.handler_line) {
        this.handler_line.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler_line.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        this.handler_line.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      }
      //移除面积测量
      if(this.handler_area) {
        this.handler_area.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler_area.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        this.handler_area.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      }
      //移除剖面分析
      if(this.handler_section) {
        this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        this.section_show=false
        this.section_data={}
      }
      //移除可视域分析
      for(var i=0;i<arrViewField.length;i++) {
        arrViewField[i].destroy()
      }
      arrViewField=[];
      //移除通视分析
      if(this.handler_visible) {
        this.handler_visible.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler_visible.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      }
      //清空绘制数据
      positions=[];
      activeShapePoints=[];
      activeShape=undefined;
      floatingPoint=undefined;
      p=[];
    },


    /*
    * 天气效果相关
    */

    //天气效果 - 菜单按钮
    menu_weather() {
      this.menu_clear();
      this.showDialog_weather=true;
      this.weather_change(this.weather_option);
    },

    //天气效果切换
    weather_change(label) {
      //晴天 多云 雾天 雨天 雪天 樱花
      switch(label) {
        case '晴天':
          if(weather) weather.destroy();
          viewer.shadows=true; //阴影
          viewer.shadowMap.enabled=true;
          viewer.shadowMap.size=2048*2;
          viewer.shadowMap.darkness=0.6;//阴影强度
          viewer.shadowMap.softShadows=true;
          viewer.shadowMap.maximumDistance=10000.0;
          //设置当前时间，阴影角度随时间变化
          viewer.clock.currentTime=Cesium.JulianDate.fromDate(new Date());
          break
        case '雾天':
          viewer.shadows=false;
          if(weather) weather.destroy();
          weather=new Cesium.FogEffect(viewer,{
            visibility: 0.2,
            color: new Cesium.Color(0.8,0.8,0.8,0.3)
          });
          break
        case '雨天':
          viewer.shadows=false;
          if(weather) weather.destroy();
          weather=new Cesium.RainEffect(viewer,{
            tiltAngle: -.6, //倾斜角度
            rainSize: 0.6, //雨大小
            rainSpeed: 120.0 //雨速
          });
          break
        case '雪天':
          viewer.shadows=false;
          if(weather) weather.destroy();
          weather=new Cesium.SnowEffect(viewer,{
            snowSize: 0.02, // 雪花大小
            snowSpeed: 60.0, // 雪速
          })
          break
        default:
          break
      }
    },


    /* 场景特效相关 */

    //场景特效 - 菜单按钮
    menu_particle() {
      this.menu_clear();
      this.showDialog_particle=true;
      this.particle_change(this.particle_option);
    },

    //场景特效选择
    particle_change(label) {
      switch(label) {
        case '樱花':
          this.clear_particle();
          this.show_flowers('樱花');
          break
        case '桂花':
          this.clear_particle();
          this.show_flowers('桂花');
          break
        case '烟花':
          this.clear_particle()
          this.show_fireworks();
          break
        default:
          break
      }
    },

    //清空场景特效
    clear_particle() {
      //移除粒子落花
      if(flower) flower.destroy();
      //移除粒子烟花
      for(var i=0;i<fireworks.length;i++) {
        fireworks[i].destroy()
      }
      fireworks=[];
    },

    //展示粒子落花
    show_flowers(label) {
      var position=Cesium.Cartesian3.add(
        new Cesium.Cartesian3(0.0,0.0,0.01),
        new Cesium.Cartesian3(0,0,0),
        new Cesium.Cartesian3()
      );
      //从发射位置创建表示转换的Matrix4
      var emitterModelMatrix=Cesium.Matrix4.fromTranslation(position);
      var flowerOption={ //粒子系统-雪配置项
        modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。
        emitterModelMatrix: emitterModelMatrix,//在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵
        lifetime: 16.0, //粒子系统发射粒子的时间（以秒为单位）
        emitter: new Cesium.SphereEmitter(flowerRadius),  //该系统的粒子发射器
        startScale: 1.5,  //在粒子寿命开始时应用于粒子图像的初始比例
        endScale: 1.5,  //在粒子寿命结束时应用于粒子图像的最终比例。
        image: label=='樱花'? require("@/assets/yinghua.png"):require("@/assets/guihua.png"), //粒子贴图
        emissionRate: 7000.0, //每秒要发射的粒子数
        startColor: Cesium.Color.WHITE.withAlpha(0.0),  //粒子在其生命初期的颜色。
        endColor: Cesium.Color.WHITE.withAlpha(1.0),  //粒子寿命结束时的颜色。
        minimumImageSize: minimumFlowerImageSize, //设置宽度的最小范围，以高度为单位，在该范围上可以随机缩放粒子图像的尺寸(以像素为单位)
        maximumImageSize: maximumFlowerImageSize, //设置最大宽度边界，以高度为单位，在该边界以下可以随机缩放粒子图像的尺寸(以像素为单位)
        updateCallback: this.flowerUpdate, //每帧都要调用一次回调函数以更新粒子
      }
      flower=viewer.scene.primitives.add(new Cesium.ParticleSystem(flowerOption));
    },

    //展示粒子烟花
    show_fireworks() {
      //粒子发射器偏移量范围
      var xMin=-100.0;
      var xMax=100.0;
      var yMin=-80.0;
      var yMax=100.0;
      var zMin=-50.0;
      var zMax=50.0;

      //设置随机颜色选项数组
      var colorOptions=[
        Cesium.Color.TOMATO,
        Cesium.Color.CORNFLOWERBLUE,
        Cesium.Color.MEDIUMTURQUOISE,
        Cesium.Color.SALMON,
        Cesium.Color.RED,
        Cesium.Color.ROYALBLUE,
        Cesium.Color.SLATEBLUE,
        Cesium.Color.LIMEGREEN
      ];

      //创建烟花
      for(let i=0;i<numberOfFireworks;++i) {
        var x=Cesium.Math.randomBetween(xMin,xMax);
        var y=Cesium.Math.randomBetween(yMin,yMax);
        var z=Cesium.Math.randomBetween(zMin,zMax);
        var offset=new Cesium.Cartesian3(x,y,z);
        //使用提供的选项创建随机颜色
        var color=Cesium.Color.fromRandom(
          colorOptions[i%colorOptions.length]
        );
        //粒子爆炸,ParticleBurst 的数组,在周期时间发射粒子爆发
        var bursts=[];
        for(let j=0;j<3;++j) {
          bursts.push(
            new Cesium.ParticleBurst({
              time: Cesium.Math.nextRandomNumber()*lifetime, //粒子系统生命周期开始后以秒为单位的时间，将发生爆发
              minimum: burstNum, //爆发中发射的最小粒子数。
              maximum: burstNum, //爆发中发射的最大粒子数。
            })
          );
        }
        //传参，创建烟花
        this.createFirework(offset,color,bursts,i);
      }
    },

    //粒子烟花贴图
    getImage() {
      if(!Cesium.defined(particleCanvas)) {
        particleCanvas=document.createElement("canvas");
        particleCanvas.width=20;
        particleCanvas.height=20;
        const context2D=particleCanvas.getContext("2d");
        context2D.beginPath();
        //圆心x 圆心y 半径 起始角度 终止角度 逆时针
        context2D.arc(10,10,8,0,Cesium.Math.TWO_PI,true);
        context2D.closePath();
        context2D.fillStyle="rgba(255, 255, 255, 1)";
        context2D.fill();
      }
      return particleCanvas;
    },

    //创建烟花函数
    createFirework(offset,color,bursts,i) {
      var position=Cesium.Cartesian3.add(
        emitterInitialLocation,
        offset,
        new Cesium.Cartesian3()
      );
      //从发射位置创建表示转换的Matrix4
      var emitterModelMatrix=Cesium.Matrix4.fromTranslation(position);

      fireworks[i]=viewer.scene.primitives.add(
        new Cesium.ParticleSystem({
          image: this.getImage(),  //粒子贴图
          startColor: color,  //粒子在其生命初期的颜色
          endColor: color.withAlpha(0.0),//粒子在其生命结束的颜色
          particleLife: 1, //粒子生命周期
          speed: 100.0, //粒子扩散速度
          imageSize: particlePixelSize, //粒子像素大小
          emissionRate: 0,  //每秒要发射的粒子数
          emitter: new Cesium.SphereEmitter(0.1), //系统粒子发射器
          bursts: bursts, //粒子爆炸,ParticleBurst 的数组
          lifetime: lifetime, //粒子系统发射粒子的时间
          modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。
          emitterModelMatrix: emitterModelMatrix,//在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵
          loop: true //粒子循环爆发
        })
      );
    },

    //粒子落花更新回调函数
    flowerUpdate(particle) {
      //计算提供的笛卡尔坐标系的标准化形式
      Cesium.Cartesian3.normalize(
        particle.position,  //要标准化的笛卡尔坐标
        flowerGravityScratch  //结果存储对象
      );
      //将提供的笛卡尔分量乘以标准的标量
      Cesium.Cartesian3.multiplyByScalar(
        flowerGravityScratch, //要缩放的笛卡尔坐标
        //要与之相乘的标量，负值代表粒子位置下降即粒子从上往下落
        Cesium.Math.randomBetween(-1.0,-3.0),
        flowerGravityScratch  //结果存储对象
      );
      //粒子位置根据flowerGravityScratch变化
      Cesium.Cartesian3.add(
        particle.position,
        flowerGravityScratch,
        particle.position
      );
    },


    /*
    * 长度测量相关
    */

    //长度测量 - 菜单按钮
    menu_length() {
      this.menu_clear();
      positions=[];	//用来存储要计算距离的点
      activeShapePoints=[]; //动态点数组
      this.handler_line=new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      //鼠标左键
      this.handler_line.setInputAction((event) => {
        var earthPosition=viewer.scene.pickPosition(event.position);
        //计算距离
        positions.push(earthPosition);
        var disance=this.getSpaceDistance(positions);
        //如果鼠标不在地球上 则earthPosition是未定义
        if(Cesium.defined(earthPosition)) {
          //第一次点击时，通过CallbackProperty绘制动态图
          if(activeShapePoints.length===0) {
            activeShapePoints.push(earthPosition);
            //动态点通过CallbackProperty实时更新渲染
            var dynamicPositions=new Cesium.CallbackProperty(function() {
              return activeShapePoints;
            },false);
            activeShape=this.drawShape_line(dynamicPositions);//绘制动态图
          }
          //添加当前点进activeShapePoints，实时渲染动态图
          activeShapePoints.push(earthPosition);
          floatingPoint=this.drawPoint_line(earthPosition,disance);
        }
      },Cesium.ScreenSpaceEventType.LEFT_CLICK);
      //鼠标移动
      this.handler_line.setInputAction((event) => {
        if(Cesium.defined(floatingPoint)) {
          var newPosition=viewer.scene.pickPosition(event.endPosition); //获取鼠标移动最终位置
          if(Cesium.defined(newPosition)) {
            //动态去除数组中最后一个点，再添加最新一个点，保证只保留鼠标位置点
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
          }
        }
      },Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      //鼠标右键
      this.handler_line.setInputAction((event) => {
        activeShapePoints.pop();//去除最后一个动态点
        if(activeShapePoints.length) {
          this.drawShape_line(activeShapePoints);//绘制最终图
        }
        viewer.entities.remove(activeShape);//去除动态图形
        floatingPoint=undefined;
        activeShape=undefined;
        activeShapePoints=[];
        positions=[];	//清空计算距离的点数组
      },Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },

    //空间两点距离计算函数
    getSpaceDistance(positions) {
      var distance=0;
      for(var i=0;i<positions.length-1;i++) {
        //直接计算距离
        distance+=Cesium.Cartesian3.distance(positions[i],positions[i+1])
      }
      return distance.toFixed(2);
    },

    //长度测量 - 绘制点与标签
    drawPoint_line(position,textDisance) {
      var pointGeometry=viewer.entities.add({
        name: "点几何对象",
        position: position,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 6,
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 2,
          disableDepthTestDistance: 1000	//当距离在1000以下不被高程遮挡
        },
        label: {
          text: textDisance+"米",
          font: '18px sans-serif',
          fillColor: Cesium.Color.GOLD,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          outlineWidth: 2,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(20,-20),
          heightReference: Cesium.HeightReference.NONE
        }
      });
      return pointGeometry;
    },

    //长度测量 - 绘制图形
    drawShape_line(positionData) {
      var shape;
      shape=viewer.entities.add({
        polyline: {
          positions: positionData,
          width: 5.0,
          material: new Cesium.PolylineGlowMaterialProperty({
            color: Cesium.Color.GOLD,
          }),
        }
      });
      return shape;
    },


    /*
    * 面积测量相关
    */

    //面积测量 - 菜单按钮
    menu_area() {
      this.menu_clear();
      p=[];
      pCartographic=[];
      activeShapePoints=[];
      this.handler_area=new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      //鼠标左键
      this.handler_area.setInputAction((event) => {
        var earthPosition=viewer.scene.pickPosition(event.position);
        pCartographic.push(Cesium.Cartographic.fromCartesian(earthPosition));
        p.push(earthPosition);
        // 如果鼠标不在地球上 则earthPosition是未定义
        if(Cesium.defined(earthPosition)) {
          //第一次点击时，通过CallbackProperty绘制动态图
          if(activeShapePoints.length===0) {
            floatingPoint=this.drawPoint_area(earthPosition);
            activeShapePoints.push(earthPosition);
            //动态点通过CallbackProperty实时更新渲染
            var dynamicPositions=new Cesium.CallbackProperty(function() {
              //绘制模式是polygon 回调返回的值就要是PolygonHierarchy类型
              return new Cesium.PolygonHierarchy(activeShapePoints);
            },false);
            activeShape=this.drawShape_area(dynamicPositions);//绘制动态图
          }
          //添加当前点进activeShapePoints，实时渲染动态图
          activeShapePoints.push(earthPosition);
          this.drawPoint_area(earthPosition);
        }
      },Cesium.ScreenSpaceEventType.LEFT_CLICK);
      //鼠标移动
      this.handler_area.setInputAction((event) => {
        if(Cesium.defined(floatingPoint)) {
          var newPosition=viewer.scene.pickPosition(event.endPosition);     //获取鼠标移动最终位置
          if(Cesium.defined(newPosition)) {
            //动态去除数组中最后一个点，再添加最新一个点，保证只保留鼠标位置点
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
          }
        }
      },Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      //鼠标右键
      this.handler_area.setInputAction((event) => {
        activeShapePoints.pop();//去除最后一个动态点
        if(activeShapePoints.length) {
          this.drawShape_area(activeShapePoints);//绘制最终图
        }
        //计算面积
        var text=this.getArea(p);
        //添加标注
        this.addLabel(pCartographic,text);
        viewer.entities.remove(floatingPoint);//移除第一个点（重复了）
        viewer.entities.remove(activeShape);//去除动态图形
        floatingPoint=undefined;
        activeShape=undefined;
        activeShapePoints=[];
        //清空存储测量面积的点
        p=[];
        pCartographic=[];
      },Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },

    //面积测量 - 方向
    getBearing(from,to) {
      var from=Cesium.Cartographic.fromCartesian(from);
      var to=Cesium.Cartographic.fromCartesian(to);
      //度转弧度表示
      var lat1=from.latitude*radiansPerDegree;
      var lon1=from.longitude*radiansPerDegree;
      var lat2=to.latitude*radiansPerDegree;
      var lon2=to.longitude*radiansPerDegree;
      //返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值)
      var angle=-Math.atan2(
        Math.sin(lon1-lon2)*Math.cos(lat2),
        Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2)
      );
      if(angle<0) {
        angle+=Math.PI*2.0;
      }
      //弧度转角度表示
      angle=angle*degreesPerRadian;
      return angle;
    },

    /* 面积测量 - 角度 */
    getAngle(p1,p2,p3) {
      var bearing21=this.getBearing(p2,p1);
      var bearing23=this.getBearing(p2,p3);
      var angle=bearing21-bearing23;
      if(angle<0) {
        angle+=360;
      }
      return angle;
    },

    /* 面积测量 - 距离 */
    getDistance(point1,point2) {
      //根据经纬度计算出距离
      var geodesic=new Cesium.EllipsoidGeodesic();
      //设置测地线的起点和终点
      geodesic.setEndPoints(point1,point2);
      //获取起点和终点之间的表面距离
      var s=geodesic.surfaceDistance;
      //返回两点之间的距离 c等于(a方+b方)再开平方
      s=Math.sqrt(Math.pow(s,2)+Math.pow(point2.height-point1.height,2));
      return s;
    },

    //计算多边形面积
    getArea(points) {
      var res=0;
      //拆分三角曲面
      for(var i=0;i<points.length-2;i++) {
        var j=(i+1)%points.length;
        var k=(i+2)%points.length;
        var totalAngle=this.getAngle(points[i],points[j],points[k]);
        var totalAngle=totalAngle.toFixed();
        var dis_temp1=this.getDistance(pCartographic[i],pCartographic[j]);
        var dis_temp2=this.getDistance(pCartographic[j],pCartographic[k]);
        res+=dis_temp1*dis_temp2*Math.abs(Math.round(Math.sin((totalAngle*Math.PI/180))*1000000)/1000000);
      }
      //单位是平方米
      return res.toFixed(2);
    },

    //面积测量 - 添加label
    addLabel(pCartographic,text) {
      //将label添加到最后一个点上方
      var position=Cesium.Cartesian3.fromRadians(
        pCartographic[pCartographic.length-1].longitude,
        pCartographic[pCartographic.length-1].latitude,
        pCartographic[pCartographic.length-1].height)

      var label=viewer.entities.add({
        position: position,
        label: {
          text: text+"平方米",
          font: '18px sans-serif',
          fillColor: Cesium.Color.GOLD,
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          outlineWidth: 2,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(20,-20),
          heightReference: Cesium.HeightReference.NONE
        }
      });
    },

    //面积测量 - 绘制点
    drawPoint_area(position) {
      var pointGeometry=viewer.entities.add({
        name: "点几何对象",
        position: position,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 6,
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 2,
          disableDepthTestDistance: 1000	//当距离在1000以下不被高程遮挡
        }
      });
      return pointGeometry;
    },

    //面积测量 - 绘制多边形
    drawShape_area(positionData) {
      var shape;
      shape=viewer.entities.add({
        polygon: {
          hierarchy: positionData,
          material: new Cesium.ColorMaterialProperty(Cesium.Color.SKYBLUE.withAlpha(0.7))
        }
      });
      return shape;
    },


    /* 剖面分析相关 */
    menu_section() {
      this.menu_clear()
      this.handler_section=new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      //鼠标左键
      this.handler_section.setInputAction((event) => {
        var earthPosition=viewer.scene.pickPosition(event.position);
        var cartographic=Cesium.Cartographic.fromCartesian(earthPosition);

        var lng=Cesium.Math.toDegrees(cartographic.longitude);
        var lat=Cesium.Math.toDegrees(cartographic.latitude);

        positions.push(Cesium.Cartesian3.fromDegrees(lng,lat));//记录要进行插值的点

        // 如果鼠标不在地球上 则earthPosition是未定义
        if(Cesium.defined(earthPosition)) {
          //第一次点击时，通过CallbackProperty绘制动态图
          if(activeShapePoints.length===0) {
            activeShapePoints.push(earthPosition);
            //动态点通过CallbackProperty实时更新渲染
            var dynamicPositions=new Cesium.CallbackProperty(function() {
              return activeShapePoints;
            },false);
            activeShape=this.drawShape_section(dynamicPositions);//绘制动态图
          }
          //添加当前点进activeShapePoints，实时渲染动态图
          activeShapePoints.push(earthPosition);
          floatingPoint=this.drawPoint_section(earthPosition);
        }
      },Cesium.ScreenSpaceEventType.LEFT_CLICK);
      //鼠标移动
      this.handler_section.setInputAction((event) => {
        if(Cesium.defined(floatingPoint)) {
          var newPosition=viewer.scene.pickPosition(event.endPosition);     //获取鼠标移动最终位置
          if(Cesium.defined(newPosition)) {
            //动态去除数组中最后一个点，再添加最新一个点，保证只保留鼠标位置点
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
          }
        }
      },Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      //鼠标右键
      this.handler_section.setInputAction((event) => {
        star=positions[0];
        end=positions[positions.length-1];
        this.interpolation(star,end);
        this.setEchartsData(p)

        activeShapePoints.pop();//去除最后一个动态点
        if(activeShapePoints.length) {
          this.drawShape_section(activeShapePoints);//绘制最终图
        }

        viewer.entities.remove(activeShape);//去除动态图形
        floatingPoint=undefined;
        activeShape=undefined;
        activeShapePoints=[];

        //清空原来的点数组
        p=[];
        positions=[];
      },Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },

    //剖面分析 - 绘制点与标签
    drawPoint_section(position,) {
      var pointGeometry=viewer.entities.add({
        name: "点几何对象",
        position: position,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 6,
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 2,
        },
      });
      return pointGeometry;
    },

    //剖面分析 - 绘制图形
    drawShape_section(positionData) {
      var shape;
      shape=viewer.entities.add({
        polyline: {
          positions: positionData,
          width: 5.0,
          material: new Cesium.PolylineGlowMaterialProperty({
            color: Cesium.Color.GOLD,
          }),
          clampToGround: true
        }
      });
      return shape;
    },

    //样条插值
    interpolation(point1,point2) {
      var spline=new Cesium.LinearSpline({
        times: [0.0,1],
        points: [point1,point2]
      });

      for(var i=0;i<=100;i++) {
        var cartesian3=spline.evaluate(i/100);

        var cartographic=Cesium.Cartographic.fromCartesian(cartesian3);

        var lon=Cesium.Math.toDegrees(cartographic.longitude);
        var lat=Cesium.Math.toDegrees(cartographic.latitude);
        var height=viewer.scene.globe.getHeight(cartographic);

        var position={
          经度: lon,
          纬度: lat,
          高度: height
        }
        p.push(position);
      }
    },

    //显示echarts
    setEchartsData(p) {
      var section_heightData=[];
      var section_position=[];
      for(var i=0;i<p.length;i++) {
        section_heightData.push(p[i].高度.toFixed(4));
        var pos=p[i].经度.toFixed(4)+","+p[i].纬度.toFixed(4);
        section_position.push(pos);
      }
      this.section_data.position=section_position
      this.section_data.heightData=section_heightData
      this.section_show=true;
      this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
      this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      this.handler_section.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },


    /* 可视域分析 - 菜单按钮 */
    menu_visual_area() {
      this.menu_clear();
      var viewshed=new Cesium.ViewShed3D(viewer,{
        horizontalAngle: Number(viewModel.horizontalAngle),
        verticalAngle: Number(viewModel.verticalAngle),
      });
      arrViewField.push(viewshed)
    },

    /* 
     * 通视分析相关
     */

    //通视分析 - 菜单按钮
    menu_visible() {
      this.menu_clear();
      this.handler_visible=new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      //鼠标左键点击事件
      this.handler_visible.setInputAction((evt) => {
        var pickedObject=viewer.scene.pick(evt.position); //判断是否拾取到模型
        if(viewer.scene.pickPositionSupported&&Cesium.defined(pickedObject)) {
          var cartesian=viewer.scene.pickPosition(evt.position);
          if(Cesium.defined(cartesian)) {
            //保证每次只有一个观察点和一个目标点
            if(positions_visble.length<2) {
              this.drawPoint_visible(cartesian);
              positions_visble.push(cartesian);
            }
            else {
              this.$message.info("请点击鼠标右键进行分析！");
            }
          }
        }
      },Cesium.ScreenSpaceEventType.LEFT_CLICK)
      //鼠标右键点击事件
      this.handler_visible.setInputAction((evt) => {
        if(positions_visble.length==2) {
          this.startAnaly(positions_visble);
          positions_visble=[];//每次绘制完线清空坐标点数组
        }
        else {
          this.$message.error("观察点和目标点是唯一的！");
        }
        positions_visble=[];//每次绘制完线清空坐标点数组
      },Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    },

    //通视分析 - 绘制点
    drawPoint_visible(position) {
      var pointGeometry=viewer.entities.add({
        name: "点几何对象",
        position: position,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 6,
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 2,
        }
      });
      return pointGeometry;
    },

    //通视分析 - 绘制线
    drawLine_visible(startPosition,endPosition,color) {
      viewer.entities.add({
        polyline: {
          positions: [startPosition,endPosition],
          width: 2,
          material: color,
          depthFailMaterial: color //用于指定折线低于地形时用于绘制折线的材料
        }
      });
    },

    //通视分析
    startAnaly(positions_visble) {
      //计算两点分量差异
      var subtract=Cesium.Cartesian3.subtract(
        positions_visble[1],	//目标点
        positions_visble[0],	//观察点
        new Cesium.Cartesian3()
      )
      //标准化计算射线方向
      var direction=Cesium.Cartesian3.normalize(
        subtract,
        new Cesium.Cartesian3()
      );
      //创建射线
      var ray=new Cesium.Ray(positions_visble[0],direction);
      //计算交点
      var result=viewer.scene.pickFromRay(ray,[]);	//返回第一个交点
      //若有交点
      if(result!==undefined&&result!==null) {
        this.drawLine_visible(result.position,positions_visble[0],Cesium.Color.GREEN); // 可视
        this.drawLine_visible(result.position,positions_visble[1],Cesium.Color.RED); // 不可视
      }
      //没交点
      else {
        this.drawLine_visible(positions_visble[0],positions_visble[1],Cesium.Color.GREEN);
      }
    },


    /* 截图 - 菜单按钮 */
    menu_capture() {
      this.menu_clear();
      var saveLink=document.createElement('a');//创建下载链接标签<a>
      var image=new Image();//创建img对象
      viewer.render();//重新渲染界面
      image=viewer.scene.canvas.toDataURL("image/png");//获取下载链接
      saveLink.href=image;	//设置下载链接
      saveLink.download='当前场景';	//设置下载图片名称
      document.body.appendChild(saveLink); //将 <a>标签 添加到 <body> 中
      saveLink.click(); 	//点击<a>标签
    },

  }
};
</script>


<style lang="scss" scoped>
#cesiumContainer {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
.cesiumContainer_right {
  position: relative;
  left: 28%;
  width: 72%;
}

::v-deep .cesium-widget-credits {
  display: none !important;
  visibility: hide !important;
}

#mouse_position {
  position: absolute;
  bottom: 0px;
  right: 8px;
}

#menu {
  position: absolute;
  right: 16px;
  top: 100px;
  width: 96px;
  background-color: rgba(55, 76, 112, 0.4);
  border-radius: 8px;
  user-select: none;
  .item_list {
    display: flex;
    height: 680px;
    width: 96px;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
    padding: 12px;
    .menu-item {
      padding: 8px 0;
      width: 80px;
      text-align: center;
      border-bottom: solid 1px rgba(91, 160, 250, 0.5);
      .iconfont {
        display: block;
        margin-bottom: 16px;
        color: #4c96f9;
        font-size: 32px;
        cursor: pointer;
      }
    }
    .menu-item:last-child {
      border: none;
    }
  }
}

.dialog {
  position: absolute;
  right: 120px;
  top: 100px;
  padding: 12px;
  border-radius: 8px;
  background-color: rgba(55, 76, 112, 0.6);
  user-select: none;
  .title {
    margin-bottom: 12px;
    i {
      float: right;
      font-size: 20px;
    }
  }
}

.particle_dialog {
  top: 180px;
}

#info-box {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 28%;
  background-color: rgba(34, 52, 87, 0.8);
  .shouqi {
    position: absolute;
    right: -4px;
    top: 48%;
    transform: translateY(-48%);
    color: #67a1e5;
    font-size: 30px;
    z-index: 9999;
  }
  .item {
    height: 33.3%;
    margin-bottom: 4px;
    .title {
      font-size: 20px;
      line-height: 30px;
      padding-left: 12px;
      width: 220px;
      background-image: linear-gradient(
        to right,
        rgba(103, 161, 229, 0.8),
        rgba(103, 161, 229, 0.7),
        rgba(103, 161, 229, 0.6),
        rgba(103, 161, 229, 0.5),
        rgba(103, 161, 229, 0.4),
        rgba(103, 161, 229, 0.3),
        rgba(103, 161, 229, 0.2),
        rgba(103, 161, 229, 0.1)
      );
    }
    .content {
      height: 88%;
      width: 100%;
      .content-item {
        display: inline-block;
        width: 33%;
        height: 100%;
        margin-top: 8px;
        margin-right: 1px;
        text-align: center;
        .iconfont {
          font-size: 100px;
          line-height: 150px;
          color: #87ceff;
        }
        .value {
          font-size: 40px;
          line-height: 60px;
          //color:#FFFACD;
        }
        .type {
          font-size: 30px;
          line-height: 45px;
          color: #b5b5b5;
        }
      }
    }
  }
}
.zhankai {
  position: absolute;
  left: -6px;
  top: 48%;
  transform: translateY(-48%);
  transform: rotateY(180deg);
  color: #67a1e5;
  font-size: 30px;
  z-index: 9999;
}

#section_result {
  position: absolute;
  top: 12px;
  left: 2%;
  transform: translateX(-2%);
  z-index: 99999;
  padding: 12px;
  background-color: rgba(28, 45, 78, 0.6);
  border-radius: 12px;
}
</style>